#ifndef FILE_SYSTEM_H
#define FILE_SYSTEM_H

#include "main.h"
#include "w25q.h"
#include "configs.h"
#include "stdlib.h"


/*user define*/
#define LOADER_PAGE_SIZE 4096 // no less than 4096
#define BITMAP_SIZE 4096
#define FILE_READ_BUF_LEN 200
#define F_MALLOC pvPortMalloc
#define F_FREE vPortFree

typedef enum{
    SETTINGS_FILE,
    NORMAL_FILE,
    FLIGHT_FILE
}File_Type;

/*user define*/

typedef enum{
    BY_ID,
    BY_TYPE,
    BY_BOTH
}Find_Way;

typedef enum{
    CLOSE,
    OPEN
}File_State;

typedef enum{
    PIECE_IDLE = 0xFF,
    PIECE_MEMORY = 0x0F,
    PIECE_LOADER = 0xF0
}Piece_Use;

#define PIECE_PAGE_SIZE 256

typedef enum{
    CHECK_FILE_SYSTEM,
    FILE_SYSTEM_IDLE,
    FILE_SYSTEM_INIT
}File_System_State;

typedef struct{
    uint16_t next_avilable_piece_id;
    bool find_avilable_piece;
}Piece_Info;

typedef struct{
    Piece_Use piece_use;
    uint8_t piece_usages;
    uint16_t next_piece_id;
}Piece_memory_Info;

typedef struct{
    uint8_t raw_data[7];
    uint32_t flash_usage;
    uint16_t file_num;
    uint16_t loader_max_num;
    uint16_t next_loader_piece_id;
}Loader_Info;

typedef struct{
    File_Type file_type;
    uint16_t file_id;
    uint16_t start_piece_id;
}File_Loader_Info;

typedef struct{
    File_Loader_Info file_loader_info;
    uint32_t file_ptr_offset;
    File_State file_state;
    bool init_if;
}File_Struct;


typedef struct{
	File_Type file_type;
    int target_create_num;
    int now_num;
    bool start_create_file;
}File_system_test_moudle;

typedef struct{
    File_Struct operate_file;
    bool open_if;
    Find_Way find_way;
    File_Type tar_type;
    uint16_t tar_file_id;
    uint8_t write_buf[20];
    bool write_if;
    uint16_t write_len;
    bool read_if;
    uint8_t read_buf[20];
    uint32_t read_start_at;
    bool close_if;
    bool clear_if;
}File_Operate_test_moudle;

typedef struct{
    uint8_t file_loader_init_bytes[8];
    uint8_t piece_start_init_bytes[4];
    uint16_t max_pieces_num;
    bool file_system_init;
    File_System_State file_system_state;
    Piece_Info piece_info;
    Loader_Info loader_info;
	File_system_test_moudle file_test;
    File_Operate_test_moudle file_operate_test;
}File_System;

extern File_System file_system;

void file_system_controller(void);
void check_file_system(void);
void file_system_idle(void);
void init_file_system(void);

uint32_t piece_id_to_addr(uint16_t piece_id);
uint32_t addr_to_piece_id(uint32_t addr);
uint16_t bitmap_offset_to_start_piece_id(uint16_t bitmap_offset);
static uint16_t find_avilable_piece(void);
static int16_t find_avilable_bitmap_index(uint8_t* bit_map_buf, uint16_t buf_len);
static uint8_t find_avilable_offset_of_bitmap_data(uint8_t bitmap_data);
uint8_t piece_id_get_bitmap_bit(uint16_t piece_id);
uint8_t piece_id_get_bitmap_byte(uint16_t piece_id);
uint8_t check_bitmap_bit_usage(uint16_t piece_id);
void set_bitmap_usage(uint16_t piece_id);
void clear_bitmap_usage(uint16_t piece_id);
Piece_memory_Info get_piece_info(uint16_t piece_id);
void update_piece_next_piece_id(uint16_t now_piece_id, uint16_t new_piece_id);
uint16_t bitmap_offset_to_avilable_piece_id(uint16_t bitmap_offset);

void init_piece_format(Piece_Use piece_use, uint16_t piece_id);
uint32_t get_file_id_to_start_addr(uint16_t file_id);
void change_file_num(uint16_t file_num);

uint32_t get_lastest_loader_jump_addr(void);
uint16_t get_lastest_loader_piece_id(void);
void extern_loader_area(void);
void update_loader_info(void);
uint16_t create_file(File_Type file_type);



uint16_t flash_malloc_pieces(void);

void write_piece_data(uint8_t* write_buf, uint32_t start_addr, uint8_t write_len);
uint32_t file_system_mem_write(uint8_t* data, uint32_t start_write_addr, uint32_t data_len, Piece_Use extern_as);
bool file_system_mem_read(uint8_t* read_buf, uint32_t start_read_addr,uint32_t start_offset, uint32_t read_len);
void read_file_system_data(uint8_t* read_buf, uint32_t start_addr, uint32_t read_len);
uint32_t from_offset_to_new_start_addr(uint32_t start_addr, uint32_t offset);
uint32_t get_file_end_ptr_offset(uint16_t start_piece_id);



File_Struct open_file(Find_Way find_way, File_Type file_type, uint16_t file_id);
void file_write(File_Struct* file, uint8_t* write_data, uint32_t data_len);
void file_write_at(File_Struct* file, uint8_t* write_data, uint32_t data_len, uint32_t write_offset);
void file_write_lines(File_Struct* file, uint8_t* write_data, uint32_t data_len);
bool file_read(File_Struct* file, uint8_t* read_buf, uint32_t read_start_at, uint32_t data_len);
uint32_t file_read_piece(File_Struct* file, uint8_t* read_buf, uint16_t now_piece_id, uint8_t read_offset);
void close_file(File_Struct* file);
void clear_file(File_Struct* file);
void format_all_files(void);





#endif



/*

low bytes  ...   high bytes

LOADER:
    LIM(3 bytes) total_usages(3 bytes) file_num(2 bytes) loop(
        file_type(1 byte) file_id(2 bytes) PIECE_start_id (2 bytes)
    )(LOADER_PAGE_SIZE - 10 bytes) 
    next_loader_piece_id(2 bytes)

BITMAP:
    loop(1 bit:all used(two pieces) / 0: have space(two_pieces))
    (4096 bytes)

PIECE:
    use_state(1 byte 0x00:idle / 0x0F: memory / 0xF0: loader) pieces_usages(1 byte)
    value(252 bytes)
    next piece_id(2 bytes/ default: 0xFF 0xFF)
*/
